package com.hqd.jjvm.instructions.constants;

import com.hqd.jjvm.instructions.AbstractInstruction;
import com.hqd.jjvm.instructions.InstructionType;
import com.hqd.jjvm.rtda.JThread;
import com.hqd.jjvm.rtda.heap.JClass;
import com.hqd.jjvm.rtda.heap.ref.JClassRef;
import com.hqd.jjvm.rtda.obj.JString;
import com.hqd.jjvm.rtda.slot.RefSlot;

/**
 * 常量指令
 */
public class ConstInstruction extends AbstractInstruction {


    public ConstInstruction(JThread jThread) {
        super(jThread);
    }

    @Override
    public void execute(InstructionType instructionType) {
        JClass currentJc = getStackFrame().getJClass();
        switch (instructionType) {
            case NOP:
                break;
            case ACONST_NULL: {
                pushSlot(new RefSlot());
                break;
            }
            case ICONST_M1: {
                pushOperandStackVal(-1);
                break;
            }
            case ICONST_0: {
                pushOperandStackVal(0);
                break;
            }
            case ICONST_1: {
                pushOperandStackVal(1);
                break;
            }
            case ICONST_2: {
                pushOperandStackVal(2);
                break;
            }
            case ICONST_3: {
                pushOperandStackVal(3);
                break;
            }
            case ICONST_4: {
                pushOperandStackVal(4);
                break;
            }
            case ICONST_5: {
                pushOperandStackVal(5);
                break;
            }
            case LCONST_0: {
                pushOperandStackVal(0L);
                break;
            }
            case LCONST_1: {
                pushOperandStackVal(1L);
                break;
            }
            case FCONST_0: {
                pushOperandStackVal(0F);
                break;
            }
            case FCONST_1: {
                pushOperandStackVal(1F);
                break;
            }
            case DCONST_0: {
                pushOperandStackVal(0D);
                break;
            }
            case DCONST_1: {
                pushOperandStackVal(1D);
                break;
            }
            case BIPUSH: {
                pushOperandStackVal(parseAndReadValU1());
                break;
            }
            case SIPUSH: {
                pushOperandStackVal(parseAndReadValU2());
                break;
            }
            case LDC: {
                int index = parseAndReadValU1();
                ldcVal(index, currentJc);
                break;
            }
            case LDC_W: {
                int index = parseAndReadValU2();
                ldcVal(index, currentJc);
                break;
            }
            case LDC2_W: {
                int index = parseAndReadValU2();
                Object val = currentJc.getConstantPool().getConstantVal(index);
                pushOperandStackObjVal(val);
                break;
            }
        }
    }

    private void ldcVal(int index, JClass currentJc) {
        try {
            Object val = currentJc.getConstantPool().getConstantVal(index);
            if (val instanceof Integer) {
                pushOperandStackVal((Integer) val);
            } else if (val instanceof Float) {
                pushOperandStackVal((Float) val);
            } else if (val instanceof String) {
                JString jString = currentJc.getConstantPool().getStringPool().getStringVal(val.toString());
                pushOperandStackVal(jString);
            } else if (val instanceof JClassRef) {
                String className = ((JClassRef) val).getClassName();
                JClass jc = currentJc.getLoader().loadJClass(className);
                pushOperandStackVal(jc.getJObject());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
